package work;

import java.io.FileNotFoundException;
import java.io.IOException;

import intf.IBorder;
import intf.IDataSource;
import intf.ILevel;
import intf.IResult;
import ru.ts.common.misc.ICmdArgs;
import ru.ts.common.misc.Text;

/**
 * Main class for the Pikovskii project
 */

/**
 * @author sigolaev_va
 * 
 */
public class Main
{

	// private static String m_KMLPath;
	private static String m_xyPath;
	/**
	 * Border path (if exists)
	 */
	private static String m_bPath;
	private static boolean m_csv;
	private static double m_R = -1D;
	private static double m_N1 = -1D;
	private static double m_N2 = -1D;
	private static String m_boundaryPath;

	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main( String[] args ) throws IOException
	{
		Text.sout("+++ START Pikovskii algorithm test ---");
		try
		{
			// 1. Check possible command line arguments, later add GUI to get
			// data
			if ( !parseArgs(args) )
			{
				help();
				return;
			}

			// 2. Read KML (or other text file) with a input data
			IDataSource src = readDataFile(getInputPath());
			
			printDS(src);

			// 3. Process
			IResult res = process(src);

			makeOutput(res);
		}
		finally
		{
			Text.sout("+++ END Pikovskii algorithm test ---");
		}
	}

	/**
	 * @param src
	 */
    private static void printDS( IDataSource src )
    {
    	Text.sout("+++ PRINT DATA SOURCE +++");
    	Text.sout( "\tBoundary length " + src.getBorder().size() + " points, R = " + src.R());
    	Text.sout("\tLevel count is " + src.getLevelCount());
    	for( int i = 0 ; i < src.getLevelCount(); i++)
    	{
    		ILevel lev = src.getLevel(i);
    		Text.sout("\tLevel #" + lev.index() + " has " + lev.lineCount() + " lines, N = " + lev.N());
    	}
    	Text.sout("--- PRINT DATA SOURCE ---");
    }

	/**
	 * @param res
	 */
	private static void makeOutput( IResult res )
	{
		// TODO Auto-generated method stub
		Processor.doOutput(res);
	}

	private static IResult process( IDataSource src )
	{
		// TODO Auto-generated method stub
		return Processor.processIt(src);
	}

	/**
	 * reads KML data into internal memory
	 * 
	 * @param iPath
	 *            path to KML, CSV etc file
	 * @return {@link IdatSource} instance created as a result
	 * @throws IOException
	 */
	private static IDataSource readDataFile( String iPath ) throws IOException
	{
		if ( m_csv )
			return ReadCSV.read(iPath);
		return null;
	}

	public static String getInputPath()
	{
		return m_xyPath;
	}

	private static void help()
	{
		Text.sout("> Help is not implemented");
	}

	private static boolean parseArgs( String[] args )
	{
		ICmdArgs cmd = new ICmdArgs.Impl(args);

		if ( cmd.hasKey('i') )
		{
			m_xyPath = cmd.value('i');
			Text.sout("+ Input path found: \"" + m_xyPath + "\"");
		}
		else
		{
			Text.sout("- Expected -i <file path> argument not found, exit with error");
			return false;
		}

		/**
		 * Read R key with radius value
		 */
		if ( !cmd.hasKey('r') )
		{
			Text.serr("- Expected -r <R> key for radius not found, exit with error");
			return false;
		}
		setR(Double.parseDouble(cmd.value('r')));

		/**
		 * Read N key with radius value
		 */
		if ( !cmd.hasKey('n') )
		{
			Text.serr("- Expected -n <N1|N2> key for N1 and N2 values not found, exit with error");
			return false;
		}
		String str = cmd.value('n');
		double nums[] = Text.splitDoubles(str, ",;|:/\\", false);
		setN1(nums[0]);
		setN2(nums[1]);

		if ( cmd.hasKey('s') )
		{
			Text.sout("+ CSV file reading will be used");
			m_csv = true;
		}
		else
		{
			Text.sout("- Expected -s key to define CSV reading not found, exit on error");
			return false;
		}

		/**
		 * Check b[oundary] key
		 */
		if ( cmd.hasKey('b') )
		{
			Text.sout("+ Boundary key found? processed");
			setBoundaryPath(cmd.value('b'));
		}
		else
		{
			Text.sout("+ Boundary path not detected, convex hull on all data will be used");
		}

		return true;
	}

	/**
	 * @return the m_R
	 */
	public static double getR()
	{
		return m_R;
	}

	/**
	 * @param m_R
	 *            the m_R to set
	 */
	public static void setR( double m_R )
	{
		Main.m_R = m_R;
	}

	/**
	 * @return the m_N1
	 */
	public static double getN1()
	{
		return m_N1;
	}

	/**
	 * @param m_N1
	 *            the m_N1 to set
	 */
	public static void setN1( double m_N1 )
	{
		Main.m_N1 = m_N1;
	}

	/**
	 * @return the m_N2
	 */
	public static double getN2()
	{
		return m_N2;
	}

	/**
	 * @param m_N2
	 *            the m_N2 to set
	 */
	public static void setN2( double m_N2 )
	{
		Main.m_N2 = m_N2;
	}

	/**
	 * Calculates parameter N for designated level
	 * 
	 * @param i
	 *            index of level
	 * @return double with value of N for designated level
	 */
	public static double getN4Level( int i )
	{
		if ( i < 0 )
			throw new IllegalArgumentException(
			        "Level index must be >= 0, detected " + i);

		switch (i)
		{
		case 0:
			return 0.0; // no N for the zero level (main separator line)
		case 1:
			return getN1(); // 200 km
			// case 2:
		default:
			return getN2(); // 100 km
		}
	}

	/**
	 * @return the m_boundaryPath
	 */
    public static String getBoundaryPath()
    {
	    return m_boundaryPath;
    }

	/**
	 * @param m_boundaryPath the m_boundaryPath to set
	 */
    public static void setBoundaryPath( String m_boundaryPath )
    {
	    Main.m_boundaryPath = m_boundaryPath;
    }

}
